#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "../comm/util.hpp"
#include "../comm/log.hpp"

namespace ns_compile
{
    using namespace ns_log;
    using namespace ns_util;
    class Compiler
    {
    public:
        Compiler() {}
        ~Compiler() {}
        // 参数：用户传入一个文件名
        // 返回值：编译是否成功
        // 编译的时候是需要形成临时文件的(comm提供)
        // 1234 -> ./temp/1234.cpp
        // 1234 -> ./temp/1234.stderr
        // 1234 -> ./temp/1234.exe
        static bool Compile(const std::string &file_name)
        {
            int pid = fork();
            if (pid < 0)
            {
                LOG(ERROR) << "内部错误， 创建子进程失败" << std::endl;
                return false;
            }
            // 子进程
            else if (pid == 0)
            {
                umask(0);
                // 创建or打开错误文件
                int stderr_fd = open(PathUtil::CompileError(file_name).c_str(), O_CREAT | O_WRONLY, 0644);
                if (stderr_fd < 0)
                {
                    LOG(WARNING) << "没有形成stderr文件" << std::endl;
                    exit(1);
                }
                // 重定向将g++打印的错误信息重定向到错误文件
                dup2(stderr_fd, 2);
                // g++ -o target.exe target.cpp -std=c++11
                execlp("g++" ,"g++", "-o", PathUtil::Exe(file_name).c_str(), PathUtil::Src(file_name).c_str(),
                       "-std=c++11", "-D", "COMPILER_ONLINE", nullptr); // 最后以nullptr结尾
                LOG(ERROR) << "g++启动错误， 可能是参数错误" << std::endl;
                exit(2);
            }
            else
            {
                // 进程等待
                waitpid(pid, nullptr, 0);
                // 通过是否形成可执行文件来判断是否编译成功
                if (FileUtil::IsFileExist(PathUtil::Exe(file_name)))
                {
                    LOG(INFO) << PathUtil::Src(file_name) << ", 编译成功 ！ " << std::endl;
                    return true;
                }
                else
                {
                    LOG(ERROR) << "没有形成形成可执行文件" << std::endl;
                    return false;
                }
            }
        }
    };
}